package ipcards;

import java.util.*;


public class CardSetControl extends ArrayList<CardSet> {

	private ArrayList<CardSet> groups = new ArrayList<CardSet>();
	private Map<Card,CardSet> cardgroup = new HashMap<Card,CardSet>();
	
	

	CardSet allcards;
	

	public CardSetControl(CardSet listOfAllCards) {
		allcards = listOfAllCards;
System.out.println("allCards in CardSetControl is of size: " + listOfAllCards.size());		
	}

	public void buildGroups(CardSet allCardsZOrdered) {

System.out.println("build" + allCardsZOrdered.size());		
		groups = new ArrayList<CardSet>();
		cardgroup = new HashMap<Card,CardSet>();
		
		for (Card c: allCardsZOrdered) {		
			ArrayList<CardSet> overlapgroups = new ArrayList<CardSet>();	// list of groups this card overlaps with
			
			for(Card other: cardgroup.keySet()) {
				if (c.overlaps(other)) {
					CardSet g = cardgroup.get(other);
					if(!overlapgroups.contains(g)) {
						overlapgroups.add(g);
					}
				}
			}
			
			CardSet mergegroup = new CardSet(c);	// new group, that has the new card in it
			
			for(CardSet g: overlapgroups) {
				mergegroup.addAll(g);
				groups.remove(g);
			}
			
			groups.add(mergegroup);
			
			for(Card cd: mergegroup) {
				cardgroup.put(cd,mergegroup);
			}
		}
	}
		
	
	public void rebuildGroups() {

		LinkedList<Card> allcardsZordered = getZOrderingConcatenated();
System.out.println("rebuild" + allcardsZordered.size() + groups.size());		
		groups = new ArrayList<CardSet>();
		cardgroup = new HashMap<Card,CardSet>();
		
		System.out.print("before: ");
		for (Card c: allcardsZordered) {
			System.out.print(c.getID() + " ");
		}
		
		for (Card c: allcardsZordered) {

			ArrayList<CardSet> overlapgroups = new ArrayList<CardSet>();	// list of groups this card overlaps with
			
			for(Card other: cardgroup.keySet()) {
				if (c.overlaps(other)) {
					CardSet g = cardgroup.get(other);
					if(!overlapgroups.contains(g)) {
						overlapgroups.add(g);
					}
				}
			}
			
			CardSet mergegroup = new CardSet(c);	// new group, that has the new card in it
			for(CardSet g: overlapgroups) {
				mergegroup.addAll(g);
				groups.remove(g);
			}
			groups.add(mergegroup);
			for(Card cd: mergegroup) {
				cardgroup.put(cd,mergegroup);
			}
		}
		
		System.out.print("after: ");
		for (Card c: allcardsZordered) {
			System.out.print(c.getID() + " ");
		}
	}
	
	
	public Collection<CardSet> getGroups() {
		return groups;
	}

	//PREFERRABLE TO METHODS BELOW
	public LinkedList<Card> getZOrderingConcatenated() {

		LinkedList<Card> allCardsZOrdered = new LinkedList<Card>();
				
		for(CardSet g: groups) {
			allCardsZOrdered.addAll(g.getZAscendingList());
		}
		
		System.out.println("getZOrderingConcatenated(): ");
		for (Card c: allCardsZOrdered) {
			System.out.print(c.getID() + " ");
		}
		return allCardsZOrdered;
	}
				
			
	
	
	//TO USE IF AND ONLY IF THE CASE ABOVE SHOULD FAIL FOR SOME UNANTICIPATED REASON
	
	public LinkedList<Card> getAllCardsZOrdered() {
		LinkedList<Card> allCardsZOrdered = new LinkedList<Card>(allcards);
		int groupnum = 0;
		int[] groupSizes = new int[groups.size()];
		for(CardSet g: groups) {
			groupSizes[groupnum] = g.size();
			groupnum++;
		}
		
		groupnum = 0;
		
		for(CardSet g: groups) {
			int[] gSizes = groupSizes;
			int diff = gSizes.length;
			int cardnum = 0;
			int position = groupnum;
			
			for(Card c: g) {
				int[] min = getMinimum(gSizes);
				while(cardnum >= min[1]) {
					diff--;
					if(min[0] < groupnum) {		//if position of minimum is before the current group
						position--;
					}
					gSizes[min[0]] = 99999999;		//reset minimum
					min = getMinimum(gSizes);
				}
				
				allCardsZOrdered.set(position, c);
				position += diff;
				cardnum++;
			}
			
			groupnum++;
		}
		
		return allCardsZOrdered;
	}
	
	private int[] getMinimum(int[] groupsizes) {
		int minimum = 99999999;
		int position = -1;
		for(int i=0; i < groupsizes.length; i++) {
			if(groupsizes[i] < minimum) {
				minimum = groupsizes[i];
				position = i;
			}
		}
		
		int[] toReturn = new int[2];
		toReturn[0] = position;
		toReturn[1] = minimum;
		return toReturn;
	}
}